package StudyCode.summary.myfile;

import java.io.*;
import java.nio.channels.FileChannel;

/**
 * 版权所有 科技与人文(www.tah1986.com)
 */
public class CopiesFilePreservingFileDates {
	public static void main(String[] argv) throws Exception {
		copyFileToDirectory(new File("E:\\迅雷下载\\test1.txt"), new File("E:\\Copy"));
	}

	private static final long FILE_COPY_BUFFER_SIZE = 1024 * 1024 * 30;

	private static void copyFileToDirectory(File srcFile, File destDir) throws IOException {
		copyFileToDirectory(srcFile, destDir, true);
	}

	private static void copyFileToDirectory(File srcFile, File destDir, boolean preserveFileDate) throws IOException {
		if (destDir == null) {
			throw new NullPointerException("目标文件夹不能为 null.");
		}
		if (destDir.exists() && !destDir.isDirectory()) {
			throw new IllegalArgumentException("目标路径 '" + destDir + "'不是文件夹");
		}
		File destFile = new File(destDir, srcFile.getName());
		copyFile(srcFile, destFile, preserveFileDate);
	}

	private static void copyFile(File srcFile, File destFile,
	                             boolean preserveFileDate) throws IOException {
		if (srcFile == null) {
			throw new NullPointerException("源文件不能为 null");
		}
		if (destFile == null) {
			throw new NullPointerException("目标文件夹不能为 null");
		}
		if (!srcFile.exists()) {
			throw new FileNotFoundException("源文件 '" + srcFile + "' 不存在");
		}
		if (srcFile.isDirectory()) {
			throw new IOException("源文件 '" + srcFile + "' 存在，但是是文件夹");
		}
		if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
			throw new IOException("源文件 '" + srcFile + "' 跟目标文件夹 '" + destFile + "' 相同");
		}
		File parentFile = destFile.getParentFile();
		if (parentFile != null) {
			if (!parentFile.mkdirs() && !parentFile.isDirectory()) {
				throw new IOException("目标文件夹 '" + parentFile + "' 不能被创建");
			}
		}
		if (destFile.exists() && !destFile.canWrite()) {
			throw new IOException("目标文件夹 '" + destFile + "' 存在但是只读");
		}
		doCopyFile(srcFile, destFile, preserveFileDate);
	}

	private static void doCopyFile(File srcFile, File destFile,
	                               boolean preserveFileDate) throws IOException {
		if (destFile.exists() && destFile.isDirectory()) {
			throw new IOException("目标文件夹 '" + destFile
					+ "' 存在，但是个目录");
		}

		FileInputStream fis = null;
		FileOutputStream fos = null;
		FileChannel input = null;
		FileChannel output = null;
		try {
			fis = new FileInputStream(srcFile);
			fos = new FileOutputStream(destFile);
			input = fis.getChannel();
			output = fos.getChannel();
			long size = input.size();
			long pos = 0;
			long count = 0;
			while (pos < size) {
				count = (size - pos) > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE
						: (size - pos);
				pos += output.transferFrom(input, pos, count);
			}
		} finally {
			closeQuietly(output);
			closeQuietly(fos);
			closeQuietly(input);
			closeQuietly(fis);
		}

		if (srcFile.length() != destFile.length()) {
			throw new IOException("失败复制文件'"
					+ srcFile + "' 到目标文件夹 '" + destFile + "'");
		}
		if (preserveFileDate) {
			destFile.setLastModified(srcFile.lastModified());
		}
	}

	private static void closeQuietly(InputStream input) {
		closeQuietly((Closeable) input);
	}

	private static void closeQuietly(OutputStream output) {
		closeQuietly((Closeable) output);
	}

	private static void closeQuietly(Closeable closeable) {
		try {
			if (closeable != null) {
				closeable.close();
			}
		} catch (IOException ioe) {
			// do nothing
		}
	}
}
